﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ArgusPCLib.Mathematics.Reflection
{
	public static class ScalarReflector
	{
		public static class PropertyNames
		{
			public const string One = "One";
			public const string Zero = "Zero";
		}

		static MethodInfo GetGetAccesor(Type scalarType, string propertyName)
		{
			PropertyInfo pi = scalarType.GetRuntimeProperty(propertyName);
			if (pi == null || pi.PropertyType != scalarType)
				throw new NotImplementedException(string.Format(Resources.Exceptions.StaticPropertyMissing,
					scalarType, scalarType, propertyName));
			MethodInfo mi = pi.GetMethod;
			if (mi == null)
				throw new NotImplementedException(string.Format(Resources.Exceptions.PublicGetAccessorMissing,
					scalarType, propertyName));
			return mi;
		}

		public static Func<IScalar> GetGetZeroHandler(Type scalarType)
		{
			MethodInfo mi = ScalarReflector.GetGetAccesor(scalarType, PropertyNames.Zero);
			return new Func<IScalar>(() => { return (IScalar)mi.Invoke(null, null); });
		}

		public static Func<T> GetGetZeroHandler<T>() where T : IScalar
		{
			MethodInfo mi = ScalarReflector.GetGetAccesor(typeof(T), PropertyNames.Zero);
			return (Func<T>)mi.CreateDelegate(typeof(Func<T>));
		}

		public static Func<IScalar> GetGetOneHandler(Type scalarType)
		{
			MethodInfo mi = ScalarReflector.GetGetAccesor(scalarType, PropertyNames.One);
			return new Func<IScalar>(() => { return (IScalar)mi.Invoke(null,null); });
		}

		public static Func<T> GetGetOneHandler<T>() where T : IScalar
		{
			MethodInfo mi = ScalarReflector.GetGetAccesor(typeof(T), PropertyNames.One);
			return (Func<T>)mi.CreateDelegate(typeof(Func<T>));
		}

		public static IScalar GetZero(Type scalarType)
		{
			MethodInfo mi = ScalarReflector.GetGetAccesor(scalarType, PropertyNames.Zero);
			return (IScalar)mi.Invoke(null, null);
		}

		public static IScalar GetOne(Type scalarType)
		{
			MethodInfo mi = ScalarReflector.GetGetAccesor(scalarType, PropertyNames.One);
			return (IScalar)mi.Invoke(null, null);
		}
	}

	public static class ScalarReflector<T> where T:IScalar
	{
		static Func<T> getZeroHandler;
		static Func<T> getOneHandler;

		static ScalarReflector()
		{
			ScalarReflector<T>.getZeroHandler = ScalarReflector.GetGetZeroHandler<T>();
			ScalarReflector<T>.getOneHandler = ScalarReflector.GetGetOneHandler<T>();
		}

		public static T Zero { get { return ScalarReflector<T>.getZeroHandler(); } }
		public static T One { get { return ScalarReflector<T>.getOneHandler(); } }
	}
}
